#include <iostream>
#include <vector>
#include <string>
#include <chrono>
#include <utility>
#include <fstream>
#include <cstdint>
bool parseEventsFile(std::vector<std::pair<double, std::vector<uint64_t>>>& events, const std::string& fileName)
{
    std::ifstream file(fileName);
    if (!file.is_open()) {
        std::cerr << "Failed to open Events file." << std::endl;
        return false;
    }
    std::string line, temp;
    bool firstLine = true;
    double timestamp_base, time;
    uint16_t type, code;
    uint32_t value;
    while (std::getline(file, line))
    {
        temp = "";
        line.erase(0, 1); // erase '['
        while (line[0] == ' ') line.erase(0, 1); // erase spaces
        while (line[0] != ']')
        {
            temp += line[0];
            line.erase(0, 1);
        }
        try {
            time = std::stod(temp);
        } catch (const std::invalid_argument& e) {
            std::cerr << "Invalid argument: " << e.what() << std::endl;
            return false;
        } catch (const std::out_of_range& e) {
            std::cerr << "Out of range: " << e.what() << std::endl;
            return false;
        } // 解析时间
        if (firstLine)
        {
            firstLine = false;
            timestamp_base = time;
        }
        time = time - timestamp_base;
        line.erase(0, 2); // erase '] '

        // 解析type
        temp = "";
        for (int i = 0; i < 4; i++)
        {
            temp += line[0];
            line.erase(0, 1);
        }
        try {
            type = std::stoull(temp, nullptr, 16);
        } catch (const std::invalid_argument& e) {
            std::cerr << "Invalid argument: " << e.what() << std::endl;
            return false;
        } catch (const std::out_of_range& e) {
            std::cerr << "Out of range: " << e.what() << std::endl;
            return false;
        }
        line.erase(0, 1); // erase ' '

        // 解析code
        temp = "";
        for (int i = 0; i < 4; i++)
        {
            temp += line[0];
            line.erase(0, 1);
        }
        try {
            code = std::stoull(temp, nullptr, 16);
        } catch (const std::invalid_argument& e) {
            std::cerr << "Invalid argument: " << e.what() << std::endl;
            return false;
        } catch (const std::out_of_range& e) {
            std::cerr << "Out of range: " << e.what() << std::endl;
            return false;
        }
        line.erase(0, 1); // erase ' '

        // 解析value
        temp = "";
        for (int i = 0; i < 8; i++)
        {
            temp += line[0];
            line.erase(0, 1);
        }
        try {
            value = std::stoull(temp, nullptr, 16);
        } catch (const std::invalid_argument& e) {
            std::cerr << "Invalid argument: " << e.what() << std::endl;
            return false;
        } catch (const std::out_of_range& e) {
            std::cerr << "Out of range: " << e.what() << std::endl;
            return false;
        }

        events.push_back({time, {type, code, value}});
    }
    std::cout << "Prase Events file successfully." << std::endl;
    return true;
}

int main()
{
    std::string eventsFileName = "/storage/emulated/0/touchEvents.txt";
    std::string inputDeviceFile = "/dev/input/event3";

    struct input_event {
        uint64_t time_int; // 时间戳整数部分
        uint64_t time_frac;// 时间戳小数部分
        uint16_t type;     // 事件类型
        uint16_t code;     // 事件代码
        uint32_t value;    // 事件值
    };

    std::vector<std::pair<double, std::vector<uint64_t>>> events;
    if (!parseEventsFile(events, eventsFileName))
        return 1;
    input_event touchEvent;
    double timestamp_base = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count() / 1000000.0;
    double timestamp = timestamp_base;
    std::cout << "Wait 5s to start." << std::endl;
    while (timestamp - timestamp_base < 5)
        timestamp = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count() / 1000000.0;
    
    std::cout << "Start!" << std::endl;
    timestamp_base = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count() / 1000000.0;
    timestamp = timestamp_base;
    std::ofstream file(inputDeviceFile, std::ios::binary);
    if (!file.is_open()) {
        std::cerr << "Failed to open file /dev/input/eventX." << std::endl;
        return 1;
    }
    for (size_t i = 0; i < events.size(); i++)
    {
        touchEvent.type = events[i].second[0];
        touchEvent.code = events[i].second[1];
        touchEvent.value = events[i].second[2];
        if (i > 0 && events[i].first != events[i - 1].first)
        {
            file.flush();
            while (timestamp - timestamp_base + 0.003 < events[i].first)
                timestamp = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count() / 1000000.0;
        }
        touchEvent.time_int = static_cast<int>(timestamp);
        touchEvent.time_frac = static_cast<int>((timestamp - touchEvent.time_int) * 1000000);
        file.write(reinterpret_cast<const char*>(&touchEvent), sizeof(input_event));
        if (file.fail()) {
            std::cerr << "Failed to write event to file /dev/input/eventX." << std::endl;
            return 1;
        }
    }
    file.close();
    return 0;
}